﻿/************************************************************************
 * AIDE - Automata Identification Engine
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     
 * Description  :     
 * Change log   :     	-Date:  Change
 ************************************************************************/
using System;
using System.Collections.Generic;

using SMLib.Base;

namespace SMLib.DataTypes
{
    /// <summary>
    /// [To Do: move this to EnGine]
    /// Implementation of a set (using a list: NEG very efficient!)
    /// </summary>
    /// <typeparam name="T">type of elements</typeparam>
    public class EnSet<T> : List<T>, IStateVariable
    {
        /// <summary>
        /// An empty set
        /// </summary>
        /// <returns>Make an empty set</returns>
        public static EnSet<T> EmptySet()
        {
            EnSet<T> emp = new EnSet<T>();
            return emp;
        }

        /// <summary>
        /// Check the equality of two objects
        /// </summary>
        /// <param name="obj">the object to be compared with</param>
        /// <returns>true if equal, false if not</returns>
        public override bool Equals(object obj)
        {
            if (!(obj is EnSet<T>))
                return false;
            EnSet<T> otherSet = (EnSet<T>)obj;
            if (Count != otherSet.Count)
                return false;
            foreach (T t in this)
                if (!otherSet.Contains(t))
                    return false;

            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="elem"></param>
        /// <returns></returns>
        public new EnSet<T> Add(T elem)
        {
            if (!this.Contains(elem))
            {
                base.Add(elem);
            }
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="elem"></param>
        public void RemoveElement(T elem)
        {
            base.Remove(elem);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="otherSet"></param>
        /// <returns></returns>
        public EnSet<T> UnionWith(EnSet<T> otherSet)
        {
            foreach (T t in otherSet)
            {
                Add(t);
            }
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="otherSet"></param>
        /// <returns></returns>
        public EnSet<T> IntersectWith(EnSet<T> otherSet)
        {
            for (int i = Count; i >= 0; i--)
            {
                if (otherSet.Contains(this[i]))
                    continue;
                else
                {
                    RemoveAt(i);
                    i++;
                }
            }
            return this;
        }

        /// <summary>
        /// Operator minus for two set
        /// </summary>
        /// <param name="otherSet"></param>
        /// <returns></returns>
        public EnSet<T> Minus(EnSet<T> otherSet)
        {
            foreach (T t in otherSet)
            {
                if (Contains(t))
                    Remove(t);
            }
            return this;
        }

        /// <summary>
        /// Clone a set
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            EnSet<T> s = new EnSet<T>();
            foreach (T t in this)
                s.Add(t);
            return s;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="otherSet"></param>
        /// <returns></returns>
        public bool IsSubsetOf(EnSet<T> otherSet)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Compute hash code of the set
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #region IState Members

        public object[] Fields
        {
            get { return null; }
        }

        public int LocationValuesCount
        {
            get { return 0; }
        }

        public string GetLocationName(int locationId)
        {
            return "";
        }

        public object GetLocation(int locationId)
        {
            return null;
        }

        #endregion

        #region IComparable Members

        public int CompareTo(object obj)
        {
            return -1;
        }

        #endregion
    }
}
